/*
 * CGI Functions Implementation
 * Author: Qoder
 * Description: Implementation of CGI functionality for HTTP server
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/sysinfo.h>
#include <sys/statvfs.h>

#include "cgi_functions.h"
#include "server_functions.h"

void process_cgi_request(int client_fd, http_request_t *request) {
    const char *cgi_path = request->path + 4; // Skip "/cgi"
    
    if (strcmp(cgi_path, "/time") == 0) {
        cgi_get_time(client_fd, request);
    } else if (strcmp(cgi_path, "/status") == 0) {
        cgi_get_status(client_fd, request);
    } else if (strcmp(cgi_path, "/version") == 0) {
        cgi_get_version(client_fd, request);
    } else if (strcmp(cgi_path, "/echo") == 0) {
        if (request->method == HTTP_POST) {
            cgi_echo_post(client_fd, request);
        } else {
            send_error_response(client_fd, HTTP_405_METHOD_NOT_ALLOWED, 
                              "POST method required for /cgi/echo");
        }
    } else {
        send_error_response(client_fd, HTTP_404_NOT_FOUND, "CGI endpoint not found");
    }
}

void cgi_get_time(int client_fd, http_request_t *request) {
    char *json_response = get_system_time_json();
    if (json_response) {
        send_json_response(client_fd, HTTP_200_OK, json_response);
        free(json_response);
    } else {
        send_error_response(client_fd, HTTP_500_INTERNAL_ERROR, 
                          "Failed to get system time");
    }
}

void cgi_get_status(int client_fd, http_request_t *request) {
    char *json_response = get_system_status_json();
    if (json_response) {
        send_json_response(client_fd, HTTP_200_OK, json_response);
        free(json_response);
    } else {
        send_error_response(client_fd, HTTP_500_INTERNAL_ERROR, 
                          "Failed to get system status");
    }
}

void cgi_get_version(int client_fd, http_request_t *request) {
    char *json_response = get_version_info_json();
    if (json_response) {
        send_json_response(client_fd, HTTP_200_OK, json_response);
        free(json_response);
    } else {
        send_error_response(client_fd, HTTP_500_INTERNAL_ERROR, 
                          "Failed to get version information");
    }
}

void cgi_echo_post(int client_fd, http_request_t *request) {
    if (!request->body || request->content_length == 0) {
        send_error_response(client_fd, HTTP_400_BAD_REQUEST, "No POST data received");
        return;
    }
    
    // Create echo response JSON
    char *json_response = malloc(request->content_length + 512);
    if (!json_response) {
        send_error_response(client_fd, HTTP_500_INTERNAL_ERROR, "Memory allocation failed");
        return;
    }
    
    snprintf(json_response, request->content_length + 512,
        "{\n"
        "  \"message\": \"Echo response\",\n"
        "  \"timestamp\": %ld,\n"
        "  \"received_data\": \"%.*s\",\n"
        "  \"content_length\": %d,\n"
        "  \"method\": \"POST\"\n"
        "}", 
        time(NULL), 
        request->content_length, 
        request->body,
        request->content_length);
    
    send_json_response(client_fd, HTTP_200_OK, json_response);
    free(json_response);
}

char *get_system_time_json(void) {
    time_t now;
    struct tm *local_time, *utc_time;
    char local_buffer[64], utc_buffer[64];
    char *json_response;
    
    time(&now);
    local_time = localtime(&now);
    utc_time = gmtime(&now);
    
    strftime(local_buffer, sizeof(local_buffer), "%Y-%m-%d %H:%M:%S", local_time);
    strftime(utc_buffer, sizeof(utc_buffer), "%Y-%m-%d %H:%M:%S", utc_time);
    
    json_response = malloc(512);
    if (!json_response) return NULL;
    
    snprintf(json_response, 512,
        "{\n"
        "  \"timestamp\": %ld,\n"
        "  \"local_time\": \"%s\",\n"
        "  \"utc_time\": \"%s\",\n"
        "  \"timezone\": \"%s\",\n"
        "  \"uptime_seconds\": %ld\n"
        "}",
        now,
        local_buffer,
        utc_buffer,
        tzname[0] ? tzname[0] : "UTC",
        (long)now - (long)time(NULL) + (long)now); // Simplified uptime calculation
    
    return json_response;
}

char *get_system_status_json(void) {
    struct sysinfo sys_info;
    struct statvfs fs_info;
    char hostname[256];
    char *json_response;
    
    if (sysinfo(&sys_info) != 0) {
        return NULL;
    }
    
    if (gethostname(hostname, sizeof(hostname)) != 0) {
        strcpy(hostname, "unknown");
    }
    
    // Get filesystem info for current directory
    if (statvfs(".", &fs_info) != 0) {
        memset(&fs_info, 0, sizeof(fs_info));
    }
    
    json_response = malloc(1024);
    if (!json_response) return NULL;
    
    snprintf(json_response, 1024,
        "{\n"
        "  \"hostname\": \"%s\",\n"
        "  \"uptime\": %ld,\n"
        "  \"load_average\": {\n"
        "    \"1min\": %.2f,\n"
        "    \"5min\": %.2f,\n"
        "    \"15min\": %.2f\n"
        "  },\n"
        "  \"memory\": {\n"
        "    \"total\": %lu,\n"
        "    \"free\": %lu,\n"
        "    \"used\": %lu,\n"
        "    \"shared\": %lu,\n"
        "    \"buffer\": %lu\n"
        "  },\n"
        "  \"processes\": %d,\n"
        "  \"disk_space\": {\n"
        "    \"total\": %lu,\n"
        "    \"free\": %lu,\n"
        "    \"available\": %lu\n"
        "  },\n"
        "  \"timestamp\": %ld\n"
        "}",
        hostname,
        sys_info.uptime,
        sys_info.loads[0] / 65536.0,
        sys_info.loads[1] / 65536.0,
        sys_info.loads[2] / 65536.0,
        sys_info.totalram,
        sys_info.freeram,
        sys_info.totalram - sys_info.freeram,
        sys_info.sharedram,
        sys_info.bufferram,
        sys_info.procs,
        (unsigned long)(fs_info.f_blocks * fs_info.f_frsize),
        (unsigned long)(fs_info.f_bfree * fs_info.f_frsize),
        (unsigned long)(fs_info.f_bavail * fs_info.f_frsize),
        time(NULL));
    
    return json_response;
}

char *get_version_info_json(void) {
    char *json_response = malloc(512);
    if (!json_response) return NULL;
    
    snprintf(json_response, 512,
        "{\n"
        "  \"server\": \"%s\",\n"
        "  \"version\": \"1.0.0\",\n"
        "  \"build_date\": \"%s %s\",\n"
        "  \"features\": [\n"
        "    \"HTTP/1.1\",\n"
        "    \"CGI Support\",\n"
        "    \"File Download\",\n"
        "    \"JSON API\",\n"
        "    \"Multi-threading\"\n"
        "  ],\n"
        "  \"endpoints\": [\n"
        "    \"GET /ping\",\n"
        "    \"GET /cgi/time\",\n"
        "    \"GET /cgi/status\",\n"
        "    \"GET /cgi/version\",\n"
        "    \"POST /cgi/echo\",\n"
        "    \"GET /download/*\"\n"
        "  ],\n"
        "  \"timestamp\": %ld\n"
        "}",
        SERVER_NAME,
        __DATE__,
        __TIME__,
        time(NULL));
    
    return json_response;
}

char *parse_query_parameter(const char *query_string, const char *param_name) {
    if (!query_string || !param_name) return NULL;
    
    char *param_start = strstr(query_string, param_name);
    if (!param_start) return NULL;
    
    // Check if it's the parameter name followed by '='
    param_start += strlen(param_name);
    if (*param_start != '=') return NULL;
    
    param_start++; // Skip '='
    
    // Find the end of the parameter value
    char *param_end = strchr(param_start, '&');
    size_t param_length = param_end ? (param_end - param_start) : strlen(param_start);
    
    // Allocate and copy the parameter value
    char *param_value = malloc(param_length + 1);
    if (!param_value) return NULL;
    
    strncpy(param_value, param_start, param_length);
    param_value[param_length] = '\0';
    
    // URL decode the parameter value
    char *decoded_value = url_decode(param_value);
    free(param_value);
    
    return decoded_value;
}

void free_cgi_response(cgi_response_t *response) {
    if (response) {
        if (response->content_type) free(response->content_type);
        if (response->body) free(response->body);
        memset(response, 0, sizeof(cgi_response_t));
    }
}